#include "target.h"
#include "phal_uart.h"

#include "../config/service_uart_config.h"

#include "service_uart.h"
#include "service_mutex.h"
#include "service_queue.h"



// *********************** DEFINITIONS *************************

#define UART_CONTROL(handle)		(*((service_uart_Control *) handle))
#define NUMBER_OF_UARTS				(sizeof(service_uart_availableUarts)/sizeof(service_uart_availableUarts[0]))

typedef struct {
	phal_uart_Id uartId;
	BOOL opened;
	service_mutex_Mutex mutexSend;
	service_mutex_Mutex mutexReceive;
	service_queue_Queue queueSend;
	service_queue_Queue queueReceive;
} service_uart_Control;

// ******************** GLOBAL VARIABLES ***********************

const phal_uart_Id service_uart_availableUarts[] = UARTS;

service_uart_Control uartControls[NUMBER_OF_UARTS];

// *********************** PROTOTYPES **************************

// *************************** BODY ****************************

////////////////////////////////////////////////////////////////
/// Init uart service										 ///
////////////////////////////////////////////////////////////////
void service_uart_init(void)
{
	U8 i;

	for(i = 0; i < NUMBER_OF_UARTS; i++)
	{
		uartControls[i].uartId = service_uart_availableUarts[i];
		uartControls[i].opened = FALSE;
		uartControls[i].mutexReceive = service_mutex_CreateMutex();
		uartControls[i].mutexSend = service_mutex_CreateMutex();
		uartControls[i].queueReceive = service_queue_CreateQueue(UART_RECEIVE_BUFFER_SIZE, sizeof(U8));
		uartControls[i].queueSend = service_queue_CreateQueue(UART_SEND_BUFFER_SIZE, sizeof(U8));
	}
}

////////////////////////////////////////////////////////////////
/// Obtain number of available ports						 ///
////////////////////////////////////////////////////////////////
U8 service_uart_getNumberOfAvailablePorts(void)
{
	return NUMBER_OF_UARTS;
}

////////////////////////////////////////////////////////////////
/// Obtain pointer to array of all available ports			 ///
////////////////////////////////////////////////////////////////
UartNumber *service_uart_getAvailablePorts(void)
{
	return (UartNumber *)service_uart_availableUarts;
}

////////////////////////////////////////////////////////////////
/// Open uart port											 ///
////////////////////////////////////////////////////////////////
UartHandle service_uart_open(UartNumber uart)
{
	U8 i;
	UartHandle result = 0;

	for(i = 0; i < NUMBER_OF_UARTS; i++)
	{
		if((service_uart_availableUarts[i] == uart)
			&& (uartControls[i].opened == FALSE))
		{
			uartControls[i].opened = TRUE;
//			if(uartControls[i].queueReceive != service_queue_INVALID_QUEUE)
//			{
//				service_queue_Delete(uartControls[i].queueReceive);
//			}
			uartControls[i].queueReceive = service_queue_CreateQueue(UART_RECEIVE_BUFFER_SIZE, sizeof(U8));
			result = (UartHandle) &uartControls[i];
		}
	}

	return result;
}

////////////////////////////////////////////////////////////////
/// Close uart port											 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_close(UartHandle handle)
{
	if(handle != 0)
	{
		UART_CONTROL(handle).opened = FALSE;
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

////////////////////////////////////////////////////////////////
/// Send one byte through uart port							 ///
////////////////////////////////////////////////////////////////
static BOOL service_uart_sendByteWithoutMutex(UartHandle handle, U8 byte)
{
	service_uart_Control uart = UART_CONTROL(handle);
	BOOL result = FALSE;

	if(service_queue_MessagesInQueue(uart.queueSend) == 0)
	{
		phal_uart_sendByte(UART_CONTROL(handle).uartId, byte);
		result = TRUE;
	}

	else if(service_queue_QueueSend(uart.queueSend, &byte, UART_SEND_TIMEOUT))
	{
		result = TRUE;
	}

	return result;
}

////////////////////////////////////////////////////////////////
/// Send one byte through uart port							 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_sendByte(UartHandle handle, U8 byte)
{
	service_uart_Control uart = UART_CONTROL(handle);
	BOOL result = FALSE;

	service_mutex_TakeMutex(uart.mutexSend, UART_SEND_TIMEOUT);

	service_uart_sendByteWithoutMutex(handle, byte);

	service_mutex_GiveMutex(uart.mutexSend);

	return result;
}

////////////////////////////////////////////////////////////////
/// Send an array of bytes through uart port				 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_sendStream(UartHandle handle, U8 *stream, U32 size)
{
	U32 i;
	service_uart_Control uart = UART_CONTROL(handle);

	service_mutex_TakeMutex(uart.mutexSend, UART_SEND_TIMEOUT);

	for (i = 0; i < size; i++) {
		if(!service_uart_sendByteWithoutMutex(handle, stream[i]))
		{
			service_mutex_GiveMutex(uart.mutexSend);
			return FALSE;
		}
	}

	service_mutex_GiveMutex(uart.mutexSend);
	return TRUE;
}

////////////////////////////////////////////////////////////////
/// Receive one byte through uart port						 ///
////////////////////////////////////////////////////////////////
static BOOL service_uart_receiveByteWithoutMutex(UartHandle handle, U8 *byte)
{
	service_uart_Control uart = UART_CONTROL(handle);
	BOOL result = FALSE;

	result = service_queue_QueueReceive(uart.queueReceive, byte, UART_RECEIVE_TIMEOUT);

	return result;
}

////////////////////////////////////////////////////////////////
/// Receive one byte through uart port						 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_receiveByte(UartHandle handle, U8 *byte)
{
	service_uart_Control uart = UART_CONTROL(handle);
	BOOL result = FALSE;

	service_mutex_TakeMutex(uart.mutexReceive, UART_RECEIVE_TIMEOUT);

	result = service_uart_receiveByteWithoutMutex(handle, byte);

	service_mutex_GiveMutex(uart.mutexReceive);

	return result;
}

////////////////////////////////////////////////////////////////
/// Receive an array of bytes through uart port				 ///
////////////////////////////////////////////////////////////////
BOOL service_uart_receiveStream(UartHandle handle, U8 *stream, U32 size)
{
	U32 i;
	service_uart_Control uart = UART_CONTROL(handle);

	service_mutex_TakeMutex(uart.mutexReceive, UART_RECEIVE_TIMEOUT);

	for (i = 0; i < size; i++) {
		if(!service_uart_receiveByteWithoutMutex(handle, &stream[i]))
		{
			service_mutex_GiveMutex(uart.mutexReceive);
			return FALSE;
		}
	}

	service_mutex_GiveMutex(uart.mutexReceive);
	return TRUE;
}

////////////////////////////////////////////////////////////////
/// Receiving byte interrupt handler						 ///
////////////////////////////////////////////////////////////////
phal_uart_DATA_RECEIVED_HANDLER(service_uart_rxHandler, args)
{
	U8 byte;
	U8 index = (U8) args;
	/* We have not woken a task at the start of the ISR. */
	BOOL higherPriorityTaskWoken = FALSE;

	byte = phal_uart_receiveByte(uartControls[index].uartId);	
	service_queue_QueueSendFromISR(uartControls[index].queueReceive, &byte, &higherPriorityTaskWoken);
}

////////////////////////////////////////////////////////////////
/// Transmitting byte interrupt handler						 ///
////////////////////////////////////////////////////////////////
phal_uart_DATA_TRANSMITTED_HANDLER(service_uart_txHandler, args)
{
	U8 uartIndex = (U8) args;
	U8 byte;

	/* We have not woken a task at the start of the ISR. */
	BOOL higherPriorityTaskWoken = FALSE;

	if(service_queue_QueueReceiveFromISR(uartControls[uartIndex].queueSend, &byte, &higherPriorityTaskWoken ))
	{
		phal_uart_sendByte(uartControls[uartIndex].uartId, byte);
	}
}

